/*
Author: Roarke Lynch
Version: 0.1.0
Description: In place menus from ULs

*/
$.extend( $.fn, {
	menu : function(command, options) {
		/***********************
		 *    Constructions    *
		 ***********************/
		$menu_container = function($e) {
			if($e.data("menu-settings") !== undefined) {
				return $e;
			}
			return $menu_container( $e.parent() );
		}
		
		$menu_for_index = function($container, index) {
			var settings = $container.data("menu-settings");
			var menu = null;
			$(settings.menuTag, $container).each(function() {
				var i = $(this).data("menu-index");
				if(i == index) {
					menu = this;
				}
			});
			return $(menu);
		}
		
		$switch_menu = function($container, nextIndex, immediate) {
			var settings = $container.data("menu-settings");
			var currentIndex = $container.data("currentMenuIndex");
			$container.data("currentMenuIndex", nextIndex);
			
			var $currentMenu = $menu_for_index($container, currentIndex);
			var $nextMenu    = $menu_for_index($container, nextIndex);
			var $back        = $("." + settings.backClass, $container);
			
			var extra = 0;
			immediate = (immediate === undefined ? false : true);
			
			if(immediate) {
				if(nextIndex == 0) {
					$back.hide();
				}
				else {
					$back.show();
					extra = settings.backHeight;
				}
				$currentMenu.hide();
				$nextMenu.show();
				
				var m_height = Number( $nextMenu.height() ) + extra;
				var m_width = $nextMenu.width();
				$container.stop().css({
					height:m_height,
					width:m_width
				});	
			}
			else {
				if(nextIndex == 0) {
					$back.fadeOut(100);
				}
				else {
					$back.fadeIn(100);
					extra = settings.backHeight;
				}
				
				$currentMenu.slideUp(100);
				$nextMenu.fadeIn(100);
				var m_height = Number( $nextMenu.height() ) + extra;
				var m_width = $nextMenu.width();
				$container.stop().animate({
					height:m_height,
					width:m_width
				}, 100);
			}
			$container.trigger("menushow", [nextIndex, $nextMenu.get(0)]);
		}
		
		$context_overlay = function(settings) {
			var $co = $("." + settings.contextOverlayClass, "body");
			if($co.length == 0) {
				$co = $(settings.contextOverlayTemplate);
				$co
					.prependTo("body")
					.append("<div class='ui-widget-overlay'</div>")
					.addClass("ui-widget")
					.addClass(settings.contextOverlayClass)
					.css({
						position:"fixed",
						top:"0px", right:"0px", bottom:"0px", left:"0px",
						zIndex:9999
					})
					.data("context-overlay-settings", settings)
					.hide();
					
				return $co;
			}
			return $co.eq(0);
		};
		
		/******************
		 *    Callbacks    *
		 ******************/
		back_callback = function(e) {
			e.stopPropagation();
			var $container = $menu_container( $(this) );
			var c_index = $container.data("currentMenuIndex");
			var $menu = $menu_for_index($container, c_index);
			var p_index = $menu.data("prev-menu-index");
			$switch_menu($container, p_index);
		}
		
		next_callback = function(e) {
			e.stopPropagation();
			var $container = $menu_container( $(this) );
			var nextIndex = $(this).data("menu-index");
			$switch_menu($container, nextIndex);
		}
		
		select_callback = function(e) {
			e.stopPropagation();
			var $container = $menu_container( $(this) );
			var c_index = $container.data("currentMenuIndex");
			var $menu = $menu_for_index($container, c_index);
			
			$container.trigger("menuselect", [ $container.get(0), $menu.get(0), this ]);
		}
		
		show_callback = function(e) {
			var $co = $(this).data("context-menu-overlay")
			var $menu = $(this).data("context-menu");
			
			var settings = $(this).data("context-menu-settings");
			
			$co.fadeIn(100).data("current-menu", $menu);
			
			switch(settings.position) {
				case 'element' :
					var os = $(this).offset();
					var top = os.top + $(this).height();
					var left = os.left;
					
					$menu
						.menu('show', 0)
						.hide()
						.css({top:top, left:left, position:"absolute"})
						.slideDown(100);
						
					break;
					
				case 'mouse' :
					var top = e.pageY;
					var left = e.pageX;
					
					$menu
						.menu('show', 0)
						.hide()
						.css({top:top-24, left:left+16, position:"absolute"})
						.slideDown(100);
						
					break;
			}
			
			return false;
		};
		
		dismiss_on_select_callback = function(e) {
			$menu = $(this);
			$co = $menu.parent();
			
			$co.fadeOut(100);
			$menu.slideUp(100);
		};
		
		dismiss_callback = function(e) {
			$co = $(this);
			$menu = $co.data("current-menu");
			
			$co.fadeOut(100);
			$menu.slideUp(100);
		};
		
		/******************
		 *    Commands    *
		 ******************/
		create = function(menu, settings) {
			$(menu).wrap(settings.containerTemplate);
			
			var $container = $(menu).parent();
			$container
				.addClass("ui-widget")
				.addClass("ui-widget-content")
				.addClass(settings.containerCorners)
				.addClass(settings.menuClass)
				.addClass(settings.containerClass)
				.data("currentMenuIndex", 0);
				
			var $back = $(settings.backTemplate);
			$back
				.text(settings.backLabel)
				.addClass("ui-widget-content")
				.addClass("ui-corner-all")
				.addClass(settings.backClass)
				.hover(
					function() {
						$(this).addClass("ui-state-hover");
					},
					function() {
						$(this).removeClass("ui-state-hover");
					}
				)
				.click(back_callback);
				
			var $backIcon = $(settings.iconTemplate);
			$backIcon
				.addClass("ui-icon")
				.addClass(settings.backIconClass)
				.addClass(settings.backIcon)
				.prependTo($back);
				
			$(settings.menuTag, $container)
				.addClass(settings.menuClass)
				.each(function(index) {
					$p_menu = $(this).parents(settings.menuTag);
					var p_index = ($p_menu.length > 0 ? $p_menu.eq(0).data("menu-index") : -1);
					$(this).data("menu-index", index);
					$(this).data("prev-menu-index", p_index);
				})
				.hide();

			$(settings.itemTag, $container)
				.addClass(settings.itemClass)
				.addClass("ui-widget-content")
				.addClass("ui-corner-all")
				.each(function() {
					if( $(this).hasClass(settings.workerClass) ) {
						
					}
					else {
						$(this).hover(
							function() {
								$(this).addClass("ui-state-hover");
							},
							function() {
								$(this).removeClass("ui-state-hover");
							}
						);
						if( $(this).children(settings.menuTag).length > 0) {
							var $menu = $(this).children(settings.menuTag).eq(0);
							var menuIndex = $menu.data("menu-index");
							
							var $icon = $(settings.iconTemplate);
							$icon
								.addClass("ui-icon")
								.addClass(settings.nextIconClass)
								.addClass(settings.nextIcon);
							
							$(this)
								.append($icon)
								.click(next_callback)
								.data("menu-index", menuIndex);
						}
						else {
							$(this).click(select_callback)
						}
					}
				});

			$(settings.menuTag, $container).each(function() {
				$(this).detach().appendTo($container);
			});
			
			$back.appendTo($container);
			settings.backHeight = Number($back.height()) + settings.backButtonAdjust;
			$container.data("menu-settings", settings);
			
			if(settings.context == null) {
				return $container;
			}
			
			var $co = $context_overlay(settings);
			$co.click(dismiss_callback);
			
			$container
				.detach()
				.appendTo($co)
				.click(function(e) { e.stopPropagation() })
				.hide();
			
			if(settings.dismissOnSelect) { 
				$container.bind("menuselect", dismiss_on_select_callback); 
			}
			
			
			var $context = $(settings.context);
			$context
				.data("context-menu-overlay", $co)
				.data("context-menu", $container)
				.data("context-menu-settings", settings)
				.bind(settings.showOn, show_callback);
			
			return $container;
		};
		
		show = function(t, index) {
			var $container = $menu_container( $(t) );
			
			$container.slideDown('fast');
			$switch_menu($container, (index === undefined ? 0 : index), true);
			
			return $container;
		};
		
		var settings = $.extend( {
			menuTag : 'ul',
			itemTag : 'li',
			
			containerCorners : "ui-corner-all",
			
			containerClass : "menu-container",
			menuClass : "menu-list",
			itemClass : "menu-item",
			nextIconClass : "menu-next-icon",
			backIconClass : "menu-back-icon",
			backClass : "menu-back",
			workerClass : "-worker-item",
			contextOverlayClass : "context-menu-overlay",
			
			containerTemplate : "<div></div>",
			iconTemplate : "<span></span>",
			backTemplate : "<div></div>",
			contextOverlayTemplate : "<div></div>",
			
			nextIcon : "ui-icon-triangle-1-e",
			backIcon : "ui-icon-triangle-1-w",
			
			backLabel : 'Back',
			backButtonAdjust : 14,
			
			context : null,
			dismissOnSelect : true,
			showOn : 'contextmenu',
			position: 'mouse' /* 'mouse' | 'element' */
			
		}, options);
		
		var t = $(this).get(0);
		
		switch(command) {
			case 'create' :
				var c = create(t, settings);
				setTimeout(function() {
					show(c, 0);
				}, 10);
				return c;
				break;
				
			case 'show' :
				return show(t, options);
				break;
		}
	}
})